package com.apes.fn.scm.retailOrder.service;

import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.model.InvoiceItem;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import com.google.common.util.concurrent.AtomicDouble;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * e 保养服务
 * 正向流程: 门店做 0元采购，然后对一新做销售； 一新生成一张对应的费用单
 *
 * @Author wuq
 * @Date 2021-8-10
 */
@Service
public class RetailInsuranceDiscountsService extends DomainService {

    @Autowired
    private ContractService contractService;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private InventoryService inventoryService;

    public void process(RetailOrder retailOrder) {
        List<Voucher> saleVouchers = voucherRepository.findAll(
                JpaDsl.toCriteriaByEq("voucherType", VoucherType.CUSTOMER_SALE, "source", retailOrder.getId(), "origin", retailOrder.getId()));
        if (saleVouchers.isEmpty()) throw new RuntimeException("没有找到对应的销售凭证");

        // 门店 对 一新的销售
        Voucher voucher = saleAccountProcess(retailOrder, saleVouchers.get(0));

        // 一新对门店的账单
        createInvoice(retailOrder, 1, voucher.getAmtTotal());
    }

    public void returnProcess(RetailOrder retailOrder, RetailOrder oldRetailOrder) {
        //获取分销凭证
        Supplier<RuntimeException> err = () -> new RuntimeException(String.format("零售单%s无法找到对应的分销凭证！请检查业务场景！", oldRetailOrder.getId()));
        Voucher saleVoucher = voucherRepository.findOne(JpaDsl.toCriteriaByEq("businessType", BusinessType.SALE_ORDER,
                "partner.id", "K1003", "company.id", oldRetailOrder.getCompany().getId(),
                "origin", oldRetailOrder.getId(), "originBusinessType", oldRetailOrder.getInnerBusinessType()
        )).orElseThrow(err);

        // 门店对一新的销售(冲红)
        crateSaleReturnVoucher(retailOrder, oldRetailOrder, saleVoucher);

        // 一新对门店的负数账单
        createInvoice(oldRetailOrder, -1, saleVoucher.getAmtTotal());
    }

    private Voucher saleAccountProcess(RetailOrder retailOrder, Voucher originSaleVoucher) {
        // 采购凭证
        Voucher purPurchase = purchaseVoucher(retailOrder);

        // 销售凭证
        return saleVoucher(retailOrder, purPurchase, originSaleVoucher);
    }

    private Voucher getDefaultVoucher(RetailOrder retailOrder, String businessType) {
        Voucher voucher = new Voucher();
        voucher.setBusinessType(businessType);
        voucher.setClerk(retailOrder.getClerk()); //业务员
        voucher.setScene(retailOrder.getScene());
        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        voucher.setSource(retailOrder.getId());
        voucher.setSourceBusinessType(retailOrder.getInnerBusinessType());
        voucher.setClassification(VoucherType.E_MAINTAIN);

        return voucher;
    }

    private Voucher purchaseVoucher(RetailOrder retailOrder) {
        Voucher purVoucher = getDefaultVoucher(retailOrder, BusinessType.PURCHASE_ORDER);
        purVoucher.setDept(retailOrder.getDept());
        purVoucher.setCompany(retailOrder.getCompany());
        purVoucher.setPartner(retailOrder.getCompany().getParty().getPatyRoleByType("Supplier"));
        Contract contract = contractService.getContract(purVoucher.getDept(), purVoucher.getPartner(), "distribution", "supplier", "零售e保养业务");
        purVoucher.setContract(contract);
        purVoucher.setInventoryMode(purVoucher.getContract().getCooperation().getInventoryMode());     //设置库存模式：寄售
        purVoucher.setAccountingMethod(purVoucher.getContract().getCooperation().getAccountingMethod());  // 核算方式：采购价
        purVoucher.setClassification(VoucherType.SERVICE_PRODUCT);
        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        // 明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();
        Product product = productRepository.findById("0002902284").get();
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());
        voucherItem.setTax(product.getTax());
        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(retailOrder.getId());
        voucherItem.setSourceItemId(retailOrder.getId());
        voucherItem.setSupplier(purVoucher.getPartner());
        voucherItem.setDiscount(0d);
        voucherItem.setPriceUnit(0);
        voucherItems.add(voucherItem);
        voucherItem.setOwner(retailOrder.getCompany());

        purVoucher.setVoucherItems(voucherItems);
        purVoucher = invoke("voucher.create", MapUtil.mapped(purVoucher));

        frostQty(purVoucher, voucherItem);  // 冻结批次

        return purVoucher;
    }

    private void frostQty(Voucher purVoucher, VoucherItem voucherItem) {
        VoucherItem purVoucherItem = purVoucher.getVoucherItems().iterator().next();    // 由于只有一个商品，这里获取第一个元素
        VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purVoucherItem).stream()
                .findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
        InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();

        inventoryService.changeFrostQty(inventoryBatch, inventoryBatch.getUom(), inventoryBatch.getPurchaseQty(),
                purVoucher.getCompany(), purVoucher.getInnerBusinessType(), purVoucher.getId(),
                String.valueOf(voucherItem.getId()), "e保养业务,门店对一新销售内部自采时, 冻结批次数量");
    }

    private Voucher saleVoucher(RetailOrder retailOrder, Voucher purVoucher, Voucher originSaleVoucher) {
        Voucher voucher = getDefaultVoucher(retailOrder, BusinessType.SALE_ORDER);

        // 来源为采购凭证
        voucher.setSource(purVoucher.getId());
        voucher.setSourceBusinessType(purVoucher.getInnerBusinessType());

        voucher.setDept(retailOrder.getDept());
        voucher.setCompany(retailOrder.getCompany());
        PartyRole partner = partyRoleRepository.findById("K1003").get();        // 为一新公司
        voucher.setPartner(partner);

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "customer", "零售e保养业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式
        voucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        //  明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = new VoucherItem();
        // e 保养商品
        Product product = productRepository.findById("0002902284").get();
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());
        voucherItem.setTax(product.getTax());
        voucherItem.setProductQty(1d);
        voucherItem.setOriginItemId(retailOrder.getId());
        voucherItem.setSourceItemId(retailOrder.getId());
        voucherItem.setOwner(retailOrder.getCompany());

        // 处理对账金额: IF (商品品类 == 机油滤清器 && 成本单价 < 15)  则对一新的销售金额减去差额部分
        // 例如一单服务APP计算的对一新结算金额为210，而“机油滤清器”的实际成本为12元，则对一新的销售金额 = 210 - (15-12) = 207
        AtomicDouble realAmt = new AtomicDouble(retailOrder.getInsuranceDiscountsAmt());
        retailOrder.getSaleItems().stream()
                .filter(item -> "M01010108002".equals(item.getProduct().getClassify().getId()))     // 找出对应的机油滤芯器商品
                .forEach(item -> {

                    // 找到对应的销售批次成本
                    VoucherItem saleItem = originSaleVoucher.getVoucherItems().stream()
                            .filter(saleVoucherItem -> saleVoucherItem.getOriginItemId().equals(item.getId())
                                    && saleVoucherItem.getProduct().getId().equals(item.getProduct().getId()))
                            .findFirst().orElseThrow(() -> new RuntimeException("根据明细行没有找到对应的凭证明细，零售单明细单号：" + item.getId()));

                    VoucherInventory vi = voucherInventoryRepository.findByVoucherItem(saleItem).stream().findFirst()
                            .orElseThrow(() -> new RuntimeException("e保养计算成本价时，没有找到对应的凭证批次数据，零售单明细单号：" + item.getId()));
                    if (vi.getInventoryBatch().getTaxCostPrice() < 15) {
                        realAmt.set(realAmt.get() - (15 - vi.getInventoryBatch().getTaxCostPrice()));
                    }
                });

        voucherItem.setPriceUnit(realAmt.get());       // 对账金额

        // 添加批次
        VoucherItem purVoucherItem = purVoucher.getVoucherItems().iterator().next();    // 由于只有一个商品，这里获取第一个元素
        VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purVoucherItem).stream()
                .findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
        voucherItem.setInventoryBatch(voucherInventory.getInventoryBatch());
        voucherItem.setSupplier(purVoucherItem.getSupplier());

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        // 创建账单
        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        // 增加账单
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
        return voucher;
    }

    /**
     * 冲红生成分销退回
     *
     * @param retailOrder
     * @return
     */
    private void crateSaleReturnVoucher(RetailOrder retailOrder, RetailOrder oldRetailOrder, Voucher saleVoucher) {
        Voucher voucher = getDefaultVoucher(oldRetailOrder, BusinessType.SALE_RETURN);
        voucher.setDept(retailOrder.getDept());
        voucher.setCompany(retailOrder.getCompany());
        voucher.setReturned(true);  // 设置为退货

        voucher.setPartner(saleVoucher.getPartner());
        voucher.setContract(saleVoucher.getContract());
        voucher.setInventoryMode(saleVoucher.getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(saleVoucher.getAccountingMethod());  // 核算方式
        voucher.setCustomerExpand(saleVoucher.getCustomerExpand());

        //  明细处理
        voucher.setVoucherItems(
                saleVoucher.getVoucherItems().stream().map(item -> {
                    VoucherItem voucherItem = new VoucherItem();
                    voucherItem.setProduct(item.getProduct());
                    voucherItem.setUom(item.getUom());
                    voucherItem.setTax(item.getTax());
                    voucherItem.setProductQty(-1.00 * item.getProductQty());
                    voucherItem.setPriceUnit(item.getPriceUnit());
                    voucherItem.setVoucherItem(item);
                    voucherItem.setOriginItemId(String.valueOf(item.getId()));
                    voucherItem.setSourceItemId(String.valueOf(item.getId()));
                    voucherItem.setOwner(retailOrder.getCompany());
                    return voucherItem;
                }).collect(Collectors.toSet()));

        // 创建凭证
        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        //创建账单
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
    }

    private Dept getDept(PartyRole company) {
        return SpringManager.getBean(DeptRepository.class)
                .findAll(JpaDsl.toCriteriaByEq("company", company, "innerTag", true))
                .stream().findFirst().orElseThrow(() -> new RuntimeException("没有找到内定标记部门，请先定义！公司：：" + company.getId()));
    }

    private void createInvoice(RetailOrder retailOrder, int type, double amt){
        Invoice invoice = new Invoice();

        invoice.setCompany(partyRoleRepository.findById("1003").get());
        invoice.setDept(getDept(invoice.getCompany()));
        invoice.setPartner(retailOrder.getCompany().getParty().getPartyRoleByType("Supplier"));   // 供应商

        invoice.setSource(retailOrder.getId());
        invoice.setSourceBusinessType(RetailOrder.class.getSimpleName());
        invoice.setOrigin(retailOrder.getId());
        invoice.setOriginBusinessType(RetailOrder.class.getSimpleName());

        invoice.setInventoryMode(InventoryMode.IM_OWN);             //设置库存模式：自有
        invoice.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销

        // 明细数据
        Set<InvoiceItem> invoiceItems = new HashSet();
        InvoiceItem invoiceItem = new InvoiceItem();
        Product product = productRepository.findOne("0002902284");    //获取挂账特殊商品
        invoiceItem.setProduct(product);

        // 获取税率
        Tax tax = SpringManager.getBean(TaxService.class).getPurchaseTax(invoice.getCompany(), invoice.getPartner(), product);
        invoiceItem.setTax(tax);

        invoiceItem.setPriceUnit(amt);
        invoiceItem.setQty(type * 1);
        invoiceItem.setUom(product.getUom());

        invoiceItem.setSourceItemId( retailOrder.getId());
        invoiceItem.setOriginItemId( retailOrder.getId() );
        invoiceItem.setPriceSubtotal( type * amt);    // 商品金额
        invoiceItems.add(invoiceItem);

        invoice.setInvoiceItems(invoiceItems);
        invoke("invoice.create", MapUtil.mapped(invoice));
    }
}
